package com.df.tools.util;

import com.df.tools.config.ConfigProperties;
import com.df.tools.msg.MsgDefinition;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
@Slf4j
public class ProtoParser {

    private final ConfigProperties configProperties;

    private HashMap<Integer, MsgDefinition> id2Def = new HashMap<>();

    List<MsgDefinition> parse() {
        List<MsgDefinition> list = new ArrayList<>();

        String protoFilePath = configProperties.getProtoFilePath();
        File file = new File(protoFilePath);
        if (!file.exists() || file.isFile()) {
            log.error("protobuf文件路径必须是一个文件夹，解析失败");
            return list;
        }
        File[] files = file.listFiles();
        List<File> protoFiles = Arrays.asList(files).stream().filter(f -> f.getName().endsWith(".proto")).collect(Collectors.toList());
        for (File protoFile : protoFiles) {
            try {
                parseFile(protoFile, list);
            } catch (Exception e) {
                log.error("解析失败，文件名：" + protoFile.getName());
                e.printStackTrace();
            }
        }

        return list;
    }

    private void parseFile(File protoFile, List<MsgDefinition> list) throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(protoFile));
        String packageName = "";
        String java_package = "";
        String java_outer_classname = "";
        List<String> collect = reader.lines().collect(Collectors.toList());



        for (String line : collect) {
            if (line.startsWith("package")) {
                packageName = line.replaceFirst("package", "").replace(";", "").trim();
            }
            if (line.startsWith("option")) {
                String temp = line.replaceFirst("option", "").trim();
                if (temp.startsWith("java_package")) {
                    java_package = optionStrClear(temp, "java_package");
                }
                if (temp.startsWith("java_outer_classname")) {
                    java_outer_classname = optionStrClear(temp, "java_outer_classname");
                }
            }
            if (!line.startsWith("message")) {
                continue;
            }

            if (packageName.equals("")) {
                log.error(StringUtl.format("{} 未配置package属性，解析失败", protoFile.getName()));
                return;
            }
            if (java_package.equals("")) {
                log.error(StringUtl.format("{} 未配置java_package属性，解析失败", protoFile.getName()));
                return;
            }
            if (java_outer_classname.equals("")) {
                log.error(StringUtl.format("{} 未配置java_outer_classname属性，解析失败", protoFile.getName()));
                return;
            }
            String message = line.replaceFirst("message", "").trim();
            if (message.endsWith("{")) {
                message = message.substring(0, message.length() - 1);
            }
            String type = checkMsgType(message);
            if(type.startsWith("unknown:")){
                log.error("有未定义的消息类型：" + type.replaceFirst("unknown:",""));
                continue;
            }
//            message = message.replaceFirst(type + "_", "");
            int msgId = message.hashCode();
            if (id2Def.containsKey(msgId)) {
                MsgDefinition old = id2Def.get(msgId);
                log.error(StringUtl.format("消息id重复，请检查。重复信息：{}.{}与{}.{}", protoFile.getName(), message, old.getName(), old.getName()));
                continue;
            }
            //eg:
            // C2S_SyncPosition(完整消息名)
            // move.proto(文件名)
            // move(文件内package参数名)
            // com.msg(文件内java_package参数名)
            // Move(文件内java_package参数名)
            MsgDefinition msgDefinition = new MsgDefinition();
            msgDefinition.setMsgId(msgId);
            msgDefinition.setFileName(protoFile.getName());
            msgDefinition.setFilePath(protoFile.getAbsolutePath());
            msgDefinition.setName(message);
            msgDefinition.setType(type);
            msgDefinition.setPackage_name(packageName);
            msgDefinition.setJava_package(java_package);
            msgDefinition.setJava_outer_classname(java_outer_classname);
            msgDefinition.setMsgFullPackage(java_package+"."+java_outer_classname);
            msgDefinition.setMsgClassName(java_outer_classname+"."+message+".class");
            list.add(msgDefinition);
            id2Def.put(msgId, msgDefinition);
        }

    }

    /**
     * 检查支持的消息类型
     * @param message
     * @return
     */
    private String checkMsgType(String message) {
        String[] s = message.split("_");
        if(s.length<=1){
            return "";
        }

        for (String msgType : configProperties.getMsgTypes()) {
            if (s[0].equals(msgType)) {
                return msgType;
            }
        }
        return "unknown:"+s[0];
    }

    private String optionStrClear(String src, String optionArg) {
        return src.replaceFirst(optionArg, "")
                .replace("=", "")
                .replace(";", "")
                .replace("\"", "")
                .trim();
    }
}
